package com.gzx.plugin.tjzy.modular.phone.complaint.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.gzx.plugin.tjzy.modular.phone.complaint.bo.GzxComplaintPhoneAddBo;
import com.gzx.plugin.tjzy.modular.phone.complaint.bo.GzxComplaintPhoneQueryBo;
import com.gzx.plugin.tjzy.modular.phone.complaint.entity.GzxComplaintPhone;
import com.gzx.plugin.tjzy.modular.phone.complaint.mapper.GzxComplaintPhoneMapper;
import com.gzx.plugin.tjzy.modular.phone.complaint.service.GzxComplaintPhoneDbService;
import com.gzx.plugin.tjzy.modular.phone.complaint.service.GzxComplaintPhoneService;
import com.gzx.plugin.tjzy.modular.phone.complaint.vo.GzxComplaintPhoneVo;
import com.gzx.plugin.tjzy.modular.phone.dto.GzxPhoneStatusDto;
import com.gzx.plugin.tjzy.modular.phone.error.dto.GzxNJXFRespDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.common.consts.IntConstant;
import vip.xiaonuo.common.mvc.service.impl.BaseServiceImpl;
import vip.xiaonuo.common.tenant.TenantContext;
import vip.xiaonuo.common.util.*;
import vip.xiaonuo.common.wechat.enums.WechatBotKeyEnum;
import vip.xiaonuo.common.wechat.enums.WechatNotificationType;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static org.apache.commons.lang.StringEscapeUtils.escapeSql;

/**
 * @author zjt
 * @description
 * @date 2025/6/10 16:59
 */
@Slf4j
@Service
@DS("tjzy-async")
public class GzxComplaintPhoneServiceImpl extends BaseServiceImpl<GzxComplaintPhoneAddBo, GzxComplaintPhoneVo, GzxComplaintPhoneQueryBo, GzxComplaintPhoneMapper, GzxComplaintPhone> implements GzxComplaintPhoneService {

    private static final String VERIFY_URL = "filter";
    private static final String BALANCE = "balance?ak=";
    private final GzxComplaintPhoneDbService complaintPhoneDbService;
    @Value("${black.xf.url}")
    private String url;
    @Value("${black.xf.ak}")
    private String ak;
    @Value("${black.xf.call-id}")
    private String callId;
    @Value("${black.xf.poly}")
    private String poly;

    public GzxComplaintPhoneServiceImpl(GzxComplaintPhoneMapper baseMapper, GzxComplaintPhoneDbService complaintPhoneDbService) {
        super(baseMapper);
        this.complaintPhoneDbService = complaintPhoneDbService;
    }

    @Override
    public void insert(GzxComplaintPhoneAddBo bo) {
        bo.setSource(2);
        bo.setBelongingMonth(Integer.valueOf(CommonDateUtil.getCurrentMonth()));
        super.insert(bo);
    }

    @Override
    public List<GzxComplaintPhone> selectList(LambdaQueryWrapper<GzxComplaintPhone> lambdaQueryWrapper) {
        return complaintPhoneDbService.selectList(lambdaQueryWrapper);
    }

    /**
     * 校验投诉手机号
     *
     * @param phoneList
     * @param userId
     * @param tenantId
     * @return
     */
    @Override
    public List<GzxPhoneStatusDto> verifyComplaint(List<String> phoneList, String userId, String tenantId) {
        List<GzxPhoneStatusDto> resultList = new ArrayList<>();
        if (CollUtil.isNotEmpty(phoneList)) {
            List<GzxComplaintPhone> complaintPhoneList = complaintPhoneDbService.selectList(Wrappers.<GzxComplaintPhone>lambdaQuery()
                    .select(GzxComplaintPhone::getPhone, GzxComplaintPhone::getType)
                    .in(GzxComplaintPhone::getPhone, phoneList.stream().map(CommonCryptogramUtil::doSm1AesEncrypt).toList())
                    .eq(GzxComplaintPhone::getBelongingMonth, CommonDateUtil.getCurrentMonth()));
            //保存到返回结果
            complaintPhoneList.forEach(s -> resultList.add(new GzxPhoneStatusDto(s.getPhone(), s.getType(), null)));
            //过滤出未在数据库命中的手机号
            List<String> missingComplaintPhoneList = phoneList.stream().filter(phone -> complaintPhoneList.stream().noneMatch(e -> e.getPhone().equals(phone))).toList();
            if (CollUtil.isNotEmpty(missingComplaintPhoneList)) {
                resultList.addAll(apiVerifyComplaint(missingComplaintPhoneList, userId, tenantId));
            }
        }
        return resultList;
    }

    /**
     * 余额告警
     */
    @Override
    public void balanceWarn() {
        try {
            String resp = CommonHttpUtil.get(url + BALANCE + ak, "南京先丰黑名单余额查询接口");
            GzxNJXFRespDto njxfRespDto = JSONObject.parseObject(resp, GzxNJXFRespDto.class);
            if (njxfRespDto != null && njxfRespDto.getData().getFirst().getBalance().compareTo(new BigDecimal("20")) < 0) {
                //余额不足
                CommonWechatUtil.sendMessage(WechatBotKeyEnum.BALANCE_WARN, WechatNotificationType.TASK_ERROR, "余额告警【异常】", List.of("GuoHaoNan-gbj"), "南京先丰投诉用户校验接口", "余额不足！！！", "当前剩余金额" + njxfRespDto.getData().getFirst().getBalance());
            }
        } catch (Exception e) {
            log.error("调用南京先丰黑名单余额查询接口出现异常", e);
        }
    }

    //导入
    @Override
    public String importExcel(GzxComplaintPhoneAddBo bo, MultipartFile multipartFile) {
        long start = System.currentTimeMillis();
        //excel的数据
        List<GzxComplaintPhoneVo> excelVoList = CommonExcelUtil.importExcel(multipartFile, GzxComplaintPhoneVo.class);
        List<GzxComplaintPhone> complaintPhoneList = MapstructUtils.convert(excelVoList, GzxComplaintPhone.class);

        if (ObjectUtils.isEmpty(complaintPhoneList)) {
            return "Excel为空";
        }

        //去掉 errorPhoneList 中 phone 为空的数据
        complaintPhoneList = complaintPhoneList.stream().filter(v -> !ObjectUtils.isEmpty(v.getPhone())).toList();

        if (ObjectUtils.isEmpty(complaintPhoneList)) {
            return "Excel为空";
        }

        //获取登录人信息
        String userId = StpLoginUserUtil.getLoginUser().getId();
        String tenantId = StpLoginUserUtil.getLoginUser().getTenantId();

        //批量处理每次1000条
        List<List<GzxComplaintPhone>> bacthList = Lists.partition(complaintPhoneList, IntConstant.VALUE_1000);
        for (List<GzxComplaintPhone> errorBatch : bacthList) {
            String batchSql = errorBatch.stream().map(s -> String.format("('%s', '%s','%s', '%s', '%s', '%s', '%s', '%s')", escapeSql(CommonCryptogramUtil.doSm1AesEncrypt(s.getPhone())), escapeSql(String.valueOf(bo.getType())), 2, CommonDateUtil.getCurrentMonth(), null, CommonDateUtil.dateTimeToStr(new Date()), escapeSql(tenantId), escapeSql(userId))).collect(Collectors.joining(", ")).replace("'null'", "null");
            baseMapper.insertBatchSql(batchSql);
            CommonSleepUtil.sleep(IntConstant.VALUE_100);
        }
        log.info("导入成功，共{}条，耗时{}秒", complaintPhoneList.size(), System.currentTimeMillis() - start);
        return "成功";
    }

    private List<GzxPhoneStatusDto> apiVerifyComplaint(List<String> phoneList, String userId, String tenantId) {
        List<GzxPhoneStatusDto> phoneStatusDtoList = new ArrayList<>();
        List<List<String>> batchPhone = Lists.partition(phoneList, IntConstant.VALUE_1000);
        for (List<String> batch : batchPhone) {
            try {
                Map<String, Object> bodyMap = new HashMap<>();
                bodyMap.put("ak", ak);
                bodyMap.put("callId", callId);
                bodyMap.put("callees", batch);
                bodyMap.put("poly", poly);
                bodyMap.put("sign", CommonCryptogramUtil.doMd5(ak + callId));
                String resp = CommonHttpUtil.post(url + VERIFY_URL, null, JSON.toJSONString(bodyMap), "南京先丰黑名单校验");
                GzxNJXFRespDto njxfRespDto = JSONObject.parseObject(resp, GzxNJXFRespDto.class);
                if (njxfRespDto != null && njxfRespDto.getErrno() == 0 && CollUtil.isNotEmpty(njxfRespDto.getData())) {
                    njxfRespDto.getData().forEach(s -> phoneStatusDtoList.add(new GzxPhoneStatusDto(s.getCallee(), s.getForbid(), JSON.toJSONString(s))));
                    Thread.startVirtualThread(() -> TenantContext.ignoreHandle(() -> complaintPhoneDbService.saveBatch(phoneStatusDtoList, userId, tenantId)));
                } else {
                    batch.forEach(s -> phoneStatusDtoList.add(new GzxPhoneStatusDto(s, 0, null)));
                }
            } catch (Exception e) {
                log.error("调用南京先丰黑名单校验出现异常", e);
                batch.forEach(s -> phoneStatusDtoList.add(new GzxPhoneStatusDto(s, 0, null)));
            }
        }
        return phoneStatusDtoList;
    }

    @Override
    protected LambdaQueryWrapper<GzxComplaintPhone> buildQueryWrapper(GzxComplaintPhoneQueryBo queryBo) {
        LambdaQueryWrapper<GzxComplaintPhone> wrapper = Wrappers.<GzxComplaintPhone>lambdaQuery()
                // 手机号
                .eq(StringUtils.isNotBlank(queryBo.getPhone()), GzxComplaintPhone::getPhone, CommonCryptogramUtil.doSm1AesEncrypt(queryBo.getPhone()))
                .eq(!ObjectUtils.isEmpty(queryBo.getType()), GzxComplaintPhone::getType, queryBo.getType())
                .eq(0 != queryBo.getBelongingMonth(), GzxComplaintPhone::getBelongingMonth, queryBo.getBelongingMonth())
                // 按照创建日期范围查询
                .between(StringUtils.isNotBlank(queryBo.getBeginTime()) && StringUtils.isNotBlank(queryBo.getEndTime()), GzxComplaintPhone::getCreateTime, queryBo.getBeginTime(), queryBo.getEndTime());
        return wrapper.orderByDesc(GzxComplaintPhone::getId);
    }
}
